#include <functional>
#include <iostream>
#include <memory>
#include <string>

#include "event.hpp"

using namespace cpp_component;

template <typename dst_type, typename src_type> dst_type pointer_cast(src_type src)
{
    return *static_cast<dst_type *>(static_cast<void *>(&src));
}

using fun_t = int(int, std::string);

int cb0(int num, std ::string key)
{
    std::cout << "cb0 " << key << " " << num << std::endl;
    return num;
}
int cb1(int num, std ::string key)
{
    std::cout << "cb1 " << key << " " << num << std::endl;
    return num;
}
int cb2(int num, std ::string key)
{
    std::cout << "cb2 " << key << " " << num << std::endl;
    return num;
}
int cb3(int num, std ::string key)
{
    std::cout << "cb3 " << key << " " << num << std::endl;
    return num;
}
int test1(void)
{
    // event<fun_t> event_test;
    // auto iter0 = event_test.subscribe("fun0", cb0);
    // auto iter1 = event_test.subscribe("fun0", cb1);
    // auto iter2 = event_test.subscribe("fun0", cb2);
    // auto iter3 = event_test.subscribe("fun0", cb3);

    // event_test.notify("fun0", 0, "test");

    // std::cout << "cb0  pointer_cast" << pointer_cast<int, fun_t>(cb0) << std::endl;
    // std::cout << "cb1  pointer_cast" << pointer_cast<int, fun_t>(cb1) << std::endl;

    // event_test.unsubscribe(iter0);
    // event_test.unsubscribe(iter0);

    // event_test.notify("fun0", 2, "test");

    // event_test.notify(L"fun1",1, "test");

    // event_test.notify_all(2, "test");
}

class BaseMessage
{
   public:
    BaseMessage() = default;
    virtual ~BaseMessage() = default;

    uint64_t getTimestamp() const
    {
        return this->timestamp;
    }
    void setTimestamp(uint64_t time)
    {
        this->timestamp = time;
    }
    float getScore() const
    {
        return this->score;
    }
    void setScore(float score)
    {
        this->score = score;
    }
    uint32_t getCode() const
    {
        return this->code;
    }
    void setCode(int code)
    {
        this->code = code;
    }
    const std::string &getContent() const
    {
        return this->content;
    }
    void setContent(const std::string &content)
    {
        this->content = content;
    }

   private:
    uint64_t timestamp;
    float score;
    uint32_t code;
    std::string content;
};

/**
 * 消息接收器
 */
using MessageReceiver = void(const std::shared_ptr<BaseMessage> message);
class msgreceiver
{
   public:
    msgreceiver()
    {
        // event<MessageReceiver> msgability;
        // msgability.subscribe("fun0", std::bind(&msgreceiver::msgreceiver101_2, this, std::placeholders::_1));
    }
    void msgreceiver101_1(const std::shared_ptr<BaseMessage> message)
    {
        std::cout << "msgreceiver101_1 " << message->getContent() << std::endl;
    }
    void msgreceiver101_2(const std::shared_ptr<BaseMessage> message)
    {
        std::cout << "msgreceiver101_2 " << message->getContent() << std::endl;
        std::cout << "msgreceiver101_2 " << message->getContent() << std::endl;
        std::cout << "msgreceiver101_2 " << message->getContent() << std::endl;
        std::cout << "msgreceiver101_2 " << message->getContent() << std::endl;
    }
};

class msgreceiver2
{
   public:
    msgreceiver2()
    {
        // event<MessageReceiver> msgability;
        // msgability.subscribe("fun0", std::bind(&msgreceiver::msgreceiver101_2, this, std::placeholders::_1));
    }
    void msgreceiver101_2(const std::shared_ptr<BaseMessage> message)
    {
        std::cout << "msgreceiver101_2 " << message->getContent() << std::endl;
    }
};

int test2(void)
{
    event<MessageReceiver> msgability;
    msgreceiver receiver;
    msgreceiver2 receiver2;
    auto fun = std::bind(&msgreceiver::msgreceiver101_1, &receiver, std::placeholders::_1);
    event<MessageReceiver>::handler iter0 = msgability.subscribe("fun0", fun);
    event<MessageReceiver>::handler iter3 = msgability.subscribe("fun0", fun);


    event<MessageReceiver>::handler iter1 = msgability.subscribe("fun0", std::bind(&msgreceiver::msgreceiver101_2, &receiver, std::placeholders::_1));
    event<MessageReceiver>::handler iter2 =
        msgability.subscribe("fun0", std::bind(&msgreceiver2::msgreceiver101_2, &receiver2, std::placeholders::_1));

    // auto msg = std::make_shared<BaseMessage>();
    // msg->setContent("this is test from main 1 ...");
    // msgability.notify("fun0", msg);

    // msgability.unsubscribe(iter0);
    // msg->setContent("this is test from main 2 ...");
    // msgability.notify("fun0", msg);
}

int main(int argc, char **argv)
{
    test1();
    test2();
}
